import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Pattern;

public class WebDocument {
    static class MentionedBook {
        public int bookId;
        public String[] authors;
        public String[] title;
        public boolean isEnclosedWithQuotes = false;
        public boolean isWithAuthor = false;
    }

    List<String> words;
    static final Pattern splitter = Pattern.compile("[^\"a-zA-Zа-яА-Я0-9]+", Pattern.MULTILINE | Pattern.UNICODE_CASE);

    public static WebDocument createFromHtml(String html) {
        Document doc = Jsoup.parse(html, "http://example.org");

        String text = doc.body().text().replace('»','"').replace('«','"');

        String[] words = splitter.split(text);

        WebDocument webDoc = new WebDocument();
        webDoc.words = new ArrayList<String>();

        for(String word : words){
            if (word.isEmpty()) continue;
            word = word.toLowerCase();
            String subword = "";
            for (char symbol : word.toCharArray()){
                if (symbol=='"'){
                    if (!subword.isEmpty()) webDoc.words.add(subword);
                    webDoc.words.add("\"");
                    subword = "";
                } else {
                    subword += symbol;
                }
            }
            if (!subword.isEmpty()) webDoc.words.add(subword);
        }

        return webDoc;
    }

    public List<String> getWords() {
        return words;
    }

    public List<MentionedBook> getRelatedBooks(BookTrie trie) {
        HashMap<Integer,MentionedBook> books = new HashMap<Integer,MentionedBook>();
        HashMap<String,HashSet<MentionedBook>> authorToBooks = new HashMap<String,HashSet<MentionedBook>>();

        HashSet<BookTrie> tries = new HashSet<BookTrie>();
        for(int i=0;i<words.size();i++)
        {
            String word = words.get(i);
            tries.add(trie);
            HashSet<BookTrie> futureTries = new HashSet<BookTrie>();
            for(BookTrie item : tries)
            {
                BookTrie next = item.getSubTrie(word);
                if (next != null)
                {
                    if (next.isFinal()) {
                        int from = i - next.getPrefix().size();
                        int to = i+1;
                        boolean isEnclosedWithQuotes =
                            from >= 0 && to < words.size() &&
                            words.get(from).equals("\"") &&
                            words.get(to).equals("\"");

                        for(BookTrieInfo bookInfo : next.getBooks()) {
                            if (!books.containsKey(bookInfo.bookId)) {
                                MentionedBook book = new MentionedBook();
                                book.bookId = bookInfo.bookId;
                                book.authors = bookInfo.authors;
                                book.title = bookInfo.title;
                                book.isEnclosedWithQuotes = false;
                                for (String author : book.authors) {
                                    if (!authorToBooks.containsKey(author)) {
                                        authorToBooks.put(author,new HashSet<MentionedBook>());
                                    }
                                    authorToBooks.get(author).add(book);
                                }
                                books.put(book.bookId, book);
                            }

                            MentionedBook book = books.get(bookInfo.bookId);
                            book.isEnclosedWithQuotes |= isEnclosedWithQuotes;
                        }
                    }
                    futureTries.add(next);
                }
            }
            tries = futureTries;
        }

        for(int i=0;i<words.size();i++) {
            if (words.get(i).length() > 1 && authorToBooks.containsKey(words.get(i))){
                for(MentionedBook book : authorToBooks.get(words.get(i))){
                    book.isWithAuthor = true;
                }
            }
        }

        ArrayList<MentionedBook> result = new ArrayList<MentionedBook>();
        for(int key : books.keySet()) {
            MentionedBook book = books.get(key);
            result.add(book);
        }
        return result;
    }
}
